`include "chunjun_define.sv" 
`include "chunjun_lib_define.sv" 
 
 //================================================================================================
// 文件名     : chunjun_tcu_bank.sv
// 创建时间   : Tue Nov  5 15:08:59 2024
// 描述       : TCU Bank模块 - 实现TCM存储器的Bank控制器
//              支持ECC错误检测与纠正、原子操作、部分写入等功能
//================================================================================================
 
module chunjun_tcu_bank #(
  parameter ID_W        = 7,        // ID位宽
  parameter LSQID_W     = 4,        // LSU队列ID位宽
  parameter DATA_W      = 64,       // 数据位宽，仅支持64或32
  parameter RAM_DATA_W  = 72,       // RAM数据位宽（包含ECC）
  parameter RAM_ADDR_W  = 13,       // RAM地址位宽
  parameter SLV_SPLIT_N = 2,        // 从设备分割数量
  parameter ECC_EN      = 0,        // ECC使能
  parameter ATOP_EN     = 0,        // 原子操作使能
  parameter WAIT_EN     = 0,        // 内存等待使能
  parameter VBANK_N     = 0         // VTCM Bank数量
)(
 
input  logic                        clk                  , //时钟信号
input  logic                        rst_n                , //复位信号
input  logic                        csr_ecc_en           , //ecc使能信号
input  logic                        icu_flush            , //来自icu的flush信号
input  logic                        icu_cancel           , //来自icu的cancel信号
input  logic [1:0]                  lsu_cancel           , //来自lsu的cancel信号
input  logic                        lsu_flush            , //来自lsu的flush信号
input  logic [LSQID_W-1:0]          lsu_flush_id         , //来自lsu的flush_id信号
input  logic [1:0]                  vpu_cancel           , //来自vpu的cancel信号
 
input  logic                        bank_req_vld_m1      , //来自bank的请求有效信号
output logic                        bank_req_rdy_m1      , //来自bank的请求就绪信号
input  logic [19:0]                 bank_req_addr_m1     , //来自bank的请求地址信号
input  logic [ID_W-1:0]             bank_req_id_m1       , //来自bank的请求id信号
input  logic                        bank_req_wr_m1       , //来自bank的请求写信号
input  logic [RAM_DATA_W-1:0]       bank_req_wdata_m1    , //来自bank的请求写数据信号
input  logic [DATA_W/8-1:0]         bank_req_wstrb_m1    , //来自bank的请求写掩码信号
input  logic [5:0]                  bank_req_atop_m1     , //来自bank的请求atop信号
input  logic [SLV_SPLIT_N-1:0]      bank_req_data_dest_m1,  // only for VTCM bank
 
output logic                        into_partial_m1      ,  // indicate the bank is being partial write
output logic                        into_atomic_m1       ,  // indicate the bank is being atomic operation
output logic                        bank_busy            , 
output logic                        bank_idle            ,  // indicate the bank do not has any infly request

output logic                        ram_cs_m1            ,  //ram_cs_m1是m1阶段的cs信号，表示请求在m1阶段cs
output logic                        ram_wr_m1            ,  //ram_wr_m1是m1阶段的wr信号，表示请求在m1阶段wr
output logic [RAM_ADDR_W-1:0]       ram_addr_m1          ,  //ram_addr_m1是m1阶段的地址信号，表示请求在m1阶段地址
output logic [RAM_DATA_W-1:0]       ram_wen_m1           ,  //ram_wen_m1是m1阶段的wen信号，表示请求在m1阶段wen
output logic [RAM_DATA_W-1:0]       ram_wdata_m1         ,  //ram_wdata_m1是m1阶段的wdata信号，表示请求在m1阶段wdata
input  logic [RAM_DATA_W-1:0]       ram_rdata_m2         ,  //ram_rdata_m2是m2阶段的rdata信号，表示请求在m2阶段rdata
 
input  logic [DATA_W-1:0]           hold_wdata           ,  // store the wdata outside of bank (for DTCM, lo and hi bank share same register)
input  logic [DATA_W/8-1:0]         hold_wstrb           ,  // store the wstrb outside of bank
input  logic [5:0]                  hold_atop            ,  // store the atop code outside of bank
input  logic [DATA_W-1:0]           hold_cmp_val         ,  // store the compare value outside of bank
 
output logic                        bank_rsp_vld_m2      ,  
output logic [ID_W-1:0]             bank_rsp_id_m2       ,
output logic [DATA_W-1:0]           bank_rsp_data_m2     ,  // data retrun in m2 (without ECC correction)
output logic                        bank_rsp_se_m2       ,  // single error 
output logic                        bank_rsp_de_m2       ,  // double error
output logic [SLV_SPLIT_N-1:0]      bank_rsp_data_dest_m2,  // only for VTCM bank
output logic [19:0]                 bank_rsp_addr_m2     ,

output logic                        bank_rsp_vld_m3      ,
output logic [ID_W-1:0]             bank_rsp_id_m3       ,
output logic [DATA_W-1:0]           bank_rsp_data_m3     ,  // data return in m3 (with ECC correction)
output logic                        bank_rsp_se_m3       ,  // single error
output logic                        bank_rsp_de_m3       ,  // double error
output logic [SLV_SPLIT_N-1:0]      bank_rsp_data_dest_m3,  // only for VTCM bank
output logic [19:0]                 bank_rsp_addr_m3     ,
output logic                        bank_atop_b_infly_m3 ,
output logic                        bank_atop_r_infly_m3 ,
 
output logic                        bank_rsp_vld_ras      ,  // the rsp in m2 only for RAS
output logic [ID_W-1:0]             bank_rsp_id_ras       ,
output logic                        bank_rsp_se_ras       ,  // single error
output logic                        bank_rsp_de_ras       ,  // double error
output logic                        bank_rsp_wr_ras       ,  // for ras interface
output logic [19:0]                 bank_rsp_addr_ras     
 
);

// 当支持ECC时：
//  - 部分写入会导致读-修改-写过程
//  - ECC单比特错误会导致在M3阶段将ECC纠正值写入RAM
//
// 当支持A扩展时：
//  - 原子操作会导致读-修改-写过程
//
// 这三种情况都会使TCM bank进入忙状态
// 但只有部分写入和原子操作会将enter_atomic_m1设为1，用于
// 寄存wdata/wstrb/atop信号 

// 原子操作编码格式：
// 6'b000000 : 无原子操作
// 6'b01e??? : 原子存储 (e=0: 小端序; e=1: be8)
// 6'b10e??? : 原子加载 (e=0: 小端序; e=1: be8)
// 6'b110000 : 原子交换
// 6'b110001 : 原子比较
//
// 原子存储/加载的atop[2:0]编码：
// 3'b000: ADD  - 加法
// 3'b001: CLR  - 清除
// 3'b010: EOR  - 异或
// 3'b011: SET  - 设置
// 3'b100: SMAX - 有符号最大值
// 3'b101: SMIN - 有符号最小值
// 3'b110: UMAX - 无符号最大值
// 3'b111: UMIN - 无符号最小值
//
// 不考虑保留的atop编码

//=================================================================================
// Local Parameters
//=================================================================================
 
// Top 4-bit of id hint request source.
// 4'b0000 - ICU
// 4'b0001 - LSU[0]
// 4'b0101 - LSU[1]
// 4'b0010 - SBU
// 4'b0011 - SLV-BUS
// 4'b1000 - VPU ld0
// 4'b1001 - VPU ld1
// 4'b1010 - VPU2VTCM
//
// ICU and LSU response at m2 stage, without ecc correction.
// SBU, SLV-BUS and VPU resposne at m3 stage, with ecc correction.

localparam EXT_ID_ICU  = 4'b0000;
localparam EXT_ID_LSU0 = 4'b0001;
localparam EXT_ID_LSU1 = 4'b0101;
localparam EXT_ID_VPU0 = 4'b1000;
localparam EXT_ID_VPU1 = 4'b1001;

localparam RAM_ADDR_OFFS = (VBANK_N == 0) ? 3 : $clog2(VBANK_N*4);
 
//=================================================================================
// Local Variables 
//=================================================================================

logic partial_wr;                    // 部分写入标志
logic atop_wr   ;                    // 原子操作写入标志
logic bank_wr_m1;                    // M1阶段bank写入标志
logic [DATA_W-1:0]       bank_wen_pre;    // 预编码的写使能信号
logic [RAM_DATA_W-1:0]   bank_wen_m1;     // M1阶段RAM写使能信号

logic                    ppln_vld_m1  ;   // M1阶段流水线有效信号
logic [19:0]             ppln_addr_m1 ;   // M1阶段流水线地址
logic [ID_W-1:0]         ppln_id_m1   ;   // M1阶段流水线ID
logic                    ppln_wr_m1   ;   // M1阶段流水线写信号
logic [DATA_W-1:0]       pre_enc_wdata_m3; // M3阶段预编码写数据
logic [DATA_W/8-1:0]     pre_enc_wstrb_m3; // M3阶段预编码写掩码
logic [DATA_W-1:0]       post_cor_rdata_m3; // M3阶段纠错后读数据
 
logic [RAM_DATA_W-1:0]   ram_rdata;       // RAM读数据
logic                    bank_self_wr_m3;  // M3阶段bank自写信号
logic [RAM_DATA_W-1:0]   post_enc_wdata_m3; // M3阶段编码后写数据
logic [RAM_DATA_W-1:0]   post_enc_wen_m3  ; // M3阶段编码后写使能
 
logic                    dff_ppln_vld_m2_set;    // M2阶段流水线有效信号设置
logic                    dff_ppln_vld_m2_clr;    // M2阶段流水线有效信号清除
logic                    dff_ppln_vld_m2_en ;    // M2阶段流水线有效信号使能
logic                    dff_ppln_vld_m2_d  ;    // M2阶段流水线有效信号数据输入
logic                    dff_ppln_vld_m2_q  ;    // M2阶段流水线有效信号数据输出
logic                    dff_ppln_vld_m2_ras_set; // M2阶段RAS流水线有效信号设置
logic                    dff_ppln_vld_m2_ras_clr; // M2阶段RAS流水线有效信号清除
logic                    dff_ppln_vld_m2_ras_en ; // M2阶段RAS流水线有效信号使能
logic                    dff_ppln_vld_m2_ras_d  ; // M2阶段RAS流水线有效信号数据输入
logic                    dff_ppln_vld_m2_ras_q  ; // M2阶段RAS流水线有效信号数据输出
logic                    dff_ppln_wr_m2_d   ;    // M2阶段流水线写信号数据输入
logic                    dff_ppln_wr_m2_q   ;    // M2阶段流水线写信号数据输出
logic                    dff_ppln_info_m2_en;    // M2阶段流水线信息使能
logic [ID_W-1:0]         dff_ppln_id_m2_d   ;    // M2阶段流水线ID数据输入
logic [ID_W-1:0]         dff_ppln_id_m2_q   ;    // M2阶段流水线ID数据输出
logic [SLV_SPLIT_N-1:0]  dff_ppln_data_dest_m2_d; // M2阶段数据目标数据输入
logic [SLV_SPLIT_N-1:0]  dff_ppln_data_dest_m2_q; // M2阶段数据目标数据输出
 
logic [19:0]             dff_ppln_addr_m2_d ;    // M2阶段流水线地址数据输入
logic [19:0]             dff_ppln_addr_m2_q ;    // M2阶段流水线地址数据输出

logic                    icu_flush_wait ;     // ICU刷新等待信号
logic                    icu_flush_m2 ;       // M2阶段ICU刷新信号
logic                    icu_cancel_wait;     // ICU取消等待信号
logic                    icu_cancel_m2;       // M2阶段ICU取消信号
logic                    lsu_cancel_wait;     // LSU取消等待信号
logic                    lsu_cancel_m2;       // M2阶段LSU取消信号
logic                    vpu_cancel_wait;     // VPU取消等待信号
logic                    vpu_cancel_m2;       // M2阶段VPU取消信号
logic                    lsu_flush_wait ;     // LSU刷新等待信号
logic                    lsu_flush_m2 ;       // M2阶段LSU刷新信号
logic                    bank_rsp_cancel_wait; // Bank响应取消等待信号
logic                    bank_rsp_cancel_m2;   // M2阶段Bank响应取消信号
logic [ID_W-1:0]         flush_id_chk_wait  ; // 刷新ID检查等待信号
logic [ID_W-1:0]         flush_id_chk_m2  ;   // M2阶段刷新ID检查信号
logic                    dff_ppln_vld_m3_set;    // M3阶段流水线有效信号设置
logic                    dff_ppln_vld_m3_clr;    // M3阶段流水线有效信号清除
logic                    dff_ppln_vld_m3_en ;    // M3阶段流水线有效信号使能
logic                    dff_ppln_vld_m3_d  ;    // M3阶段流水线有效信号数据输入
logic                    dff_ppln_vld_m3_q  ;    // M3阶段流水线有效信号数据输出
logic                    dff_ppln_wr_m3_q   ;    // M3阶段流水线写信号数据输出
logic [19:0]             dff_ppln_addr_m3_q ;    // M3阶段流水线地址数据输出
logic                    dff_ppln_id_m3_en  ;    // M3阶段流水线ID使能
logic [ID_W-1:0]         dff_ppln_id_m3_q   ;    // M3阶段流水线ID数据输出
logic                    dff_ppln_rdata_m3_en;   // M3阶段流水线读数据使能
logic [DATA_W-1:0]       dff_ppln_rdata_m3_q ;   // M3阶段流水线读数据输出
logic [SLV_SPLIT_N-1:0]  dff_ppln_data_dest_m3_q; // M3阶段数据目标输出
logic                    m2_addr_match;          // M2阶段地址匹配信号
logic                    m2_addr_match_q;        // M2阶段地址匹配信号寄存器
 
logic                    bank_bein_ptwr_m2;      // M2阶段bank开始部分写入标志
logic                    bank_bein_ptwr_m3_pre;   // M3阶段bank开始部分写入预标志
logic                    bank_bein_ptwr_m3;       // M3阶段bank开始部分写入标志
logic [DATA_W-1:0]       bank_pt_wdata_m3;       // M3阶段bank部分写入数据
logic                    ecc_dec_sec_m2;          // M2阶段ECC单比特错误检测
logic                    ecc_dec_sec_m3;          // M3阶段ECC单比特错误检测
logic                    ecc_dec_ded_m2;          // M2阶段ECC双比特错误检测
logic                    ecc_dec_ded_m3;          // M3阶段ECC双比特错误检测
logic                    bank_ecc_self_wr_m3;     // M3阶段bank ECC自写信号
 
logic                    dff_ppln_atop_infly_m2_set;    // M2阶段原子操作进行中设置信号
logic                    dff_ppln_atop_infly_m2_clr;    // M2阶段原子操作进行中清除信号
logic                    dff_ppln_atop_infly_m2_en ;    // M2阶段原子操作进行中使能信号
logic                    dff_ppln_atop_infly_m2_d  ;    // M2阶段原子操作进行中数据输入
logic                    dff_ppln_atop_infly_m2_q  ;    // M2阶段原子操作进行中数据输出
logic                    bank_atop_infly_m2        ;    // M2阶段bank原子操作进行中标志
logic                    bank_atop_infly_m3        ;    // M3阶段bank原子操作进行中标志
logic                    dff_ppln_atop_infly_m3_set;    // M3阶段原子操作进行中设置信号
logic                    dff_ppln_atop_infly_m3_clr;    // M3阶段原子操作进行中清除信号
logic                    dff_ppln_atop_infly_m3_en ;    // M3阶段原子操作进行中使能信号
logic                    dff_ppln_atop_infly_m3_d  ;    // M3阶段原子操作进行中数据输入
logic                    dff_ppln_atop_infly_m3_q  ;    // M3阶段原子操作进行中数据输出
logic                    atop_self_wr_m3;              // M3阶段原子操作自写信号
logic [DATA_W-1:0]       atop_rslt_m3;                 // M3阶段原子操作结果
 
logic [RAM_DATA_W-1:0]   dff_ppln_rdata_m2_d  ;    // M2阶段流水线读数据输入
logic [RAM_DATA_W-1:0]   dff_ppln_rdata_m2_q  ;    // M2阶段流水线读数据输出
logic                    dff_ppln_vld_wait_set;    // 等待阶段流水线有效信号设置
logic                    dff_ppln_vld_wait_clr;    // 等待阶段流水线有效信号清除
logic                    dff_ppln_vld_wait_en ;    // 等待阶段流水线有效信号使能
logic                    dff_ppln_vld_wait_d  ;    // 等待阶段流水线有效信号数据输入
logic                    dff_ppln_vld_wait_q  ;    // 等待阶段流水线有效信号数据输出
logic                    dff_ppln_wr_wait_q   ;    // 等待阶段流水线写信号输出
logic [19:0]             dff_ppln_addr_wait_q ;    // 等待阶段流水线地址输出
logic [ID_W-1:0]         dff_ppln_id_wait_q   ;    // 等待阶段流水线ID输出
logic [SLV_SPLIT_N-1:0]  dff_ppln_data_dest_wait_q;    // 等待阶段数据目标输出
logic                    bank_bein_ptwr_wait;          // 等待阶段bank开始部分写入标志
logic                    dff_ppln_atop_infly_wait_set; // 等待阶段原子操作进行中设置信号
logic                    dff_ppln_atop_infly_wait_clr; // 等待阶段原子操作进行中清除信号
logic                    dff_ppln_atop_infly_wait_en;  // 等待阶段原子操作进行中使能信号
logic                    dff_ppln_atop_infly_wait_d;   // 等待阶段原子操作进行中数据输入
logic                    dff_ppln_atop_infly_wait_q;   // 等待阶段原子操作进行中数据输出
logic                    bank_atop_infly_wait;         // 等待阶段bank原子操作进行中标志
 
//=================================================================================
// Bank Write
//=================================================================================
assign bank_wr_m1      = ppln_wr_m1 & ~(into_partial_m1 | into_atomic_m1);  //当接口为写操作，同时没有原子和部分写时，为写有效
 
assign partial_wr      = ~&bank_req_wstrb_m1 & bank_req_wr_m1; //存在部分写 & 写有效时，认为是部分写有效
assign atop_wr         = |bank_req_atop_m1[5:4]; //原子操作使能
assign bank_self_wr_m3 = bank_bein_ptwr_m3 | bank_ecc_self_wr_m3 | atop_self_wr_m3; //Bank正在进行部分写 || Bank正在进行ECC自写 || Bank正在进行原子自写
 
//=================================================================================
// RAM Interface
//=================================================================================
// ram_addr_m1 always truncate address from bit[3].
// Because whole TCM is always 64-bit data width,
// even when tcm_bank width is set to 32-bit, 
// we get a whole TCM with 2 banks (lo/hi).

assign ram_cs_m1    = ppln_vld_m1 | bank_self_wr_m3;  //使能包括接口的读写请求和读改写请求
 
assign ram_wr_m1    = bank_wr_m1 | bank_self_wr_m3;  //写包括请求的写和读改写请求

assign ram_addr_m1  = {RAM_ADDR_W{ppln_vld_m1     }} & ppln_addr_m1[RAM_ADDR_OFFS +: RAM_ADDR_W]      | //如果vld有效，则选择m1的地址
                      {RAM_ADDR_W{bank_self_wr_m3 }} & dff_ppln_addr_m3_q[RAM_ADDR_OFFS +: RAM_ADDR_W]; //如果self_wr有效，选择自写的地址

assign ram_wen_m1   = {RAM_DATA_W{bank_wr_m1     }} & bank_wen_m1    | //如果wr有效，则ram_wen_m1为bank_wen_m1
                      {RAM_DATA_W{bank_self_wr_m3}} & post_enc_wen_m3; //自写的写有效，使用自写的wen
 
assign ram_wdata_m1 = {RAM_DATA_W{ppln_vld_m1     }} & bank_req_wdata_m1 | //如果接口的写有效，则选择m1的wdata
                      {RAM_DATA_W{bank_self_wr_m3 }} & post_enc_wdata_m3 ; //如果自写的写有效，则选择自写的wdata

//=================================================================================
// Flush & Cancel Control
//=================================================================================
if (WAIT_EN) begin: g_flush_wait
 
  assign flush_id_chk_wait = dff_ppln_id_wait_q; //no use
  assign flush_id_chk_m2   = dff_ppln_id_m2_q; //no use

  assign icu_flush_wait  = (flush_id_chk_wait[ID_W-1 -: 4] == EXT_ID_ICU) & icu_flush; //no use
  assign icu_flush_m2    = (flush_id_chk_m2[ID_W-1 -: 4] == EXT_ID_ICU) & icu_flush; //no use
  assign icu_cancel_wait = (flush_id_chk_wait[ID_W-1 -: 4] == EXT_ID_ICU) & icu_cancel; //no use

  // Compare whether id is younger than flush_id.
  // - Wrap_bit equals, index (exclude wrap_bit) greater than or equal flush_index.
  // - Wrap_bit not equal, index (exclude wrap_bit) less than flush_index.
  assign lsu_flush_wait = ((flush_id_chk_wait[ID_W-1 -: 4] == EXT_ID_LSU0) |  //no use
                           (flush_id_chk_wait[ID_W-1 -: 4] == EXT_ID_LSU1) )  //no use
                        & lsu_flush //no use
                        & ( (flush_id_chk_wait[LSQID_W-1]   ^  lsu_flush_id[LSQID_W-1])    ? //no use
                            (flush_id_chk_wait[LSQID_W-2:0] <  lsu_flush_id[LSQID_W-2:0])  : //no use
                            (flush_id_chk_wait[LSQID_W-2:0] >= lsu_flush_id[LSQID_W-2:0]) ); //no use

  assign lsu_flush_m2 = ((flush_id_chk_m2[ID_W-1 -: 4] == EXT_ID_LSU0) |  //no use
                         (flush_id_chk_m2[ID_W-1 -: 4] == EXT_ID_LSU1) )  //no use
                      & lsu_flush //no use
                      & ( (flush_id_chk_m2[LSQID_W-1]   ^  lsu_flush_id[LSQID_W-1])    ? //no use
                          (flush_id_chk_m2[LSQID_W-2:0] <  lsu_flush_id[LSQID_W-2:0])  : //no use
                          (flush_id_chk_m2[LSQID_W-2:0] >= lsu_flush_id[LSQID_W-2:0]) ); //no use

  assign lsu_cancel_wait = (flush_id_chk_wait[ID_W-1 -: 4] == EXT_ID_LSU0) & lsu_cancel[0] | //no use
                           (flush_id_chk_wait[ID_W-1 -: 4] == EXT_ID_LSU1) & lsu_cancel[1] ; //no use

  assign vpu_cancel_wait = (flush_id_chk_wait[ID_W-1 -: 4] == EXT_ID_VPU0) & vpu_cancel[0] | //no use
                           (flush_id_chk_wait[ID_W-1 -: 4] == EXT_ID_VPU1) & vpu_cancel[1] ; //no use

  // TCM_WAIT: rsp_m2, rsp_m3 should be canceled
  assign bank_rsp_cancel_wait = icu_flush_wait | icu_cancel_wait | lsu_flush_wait | lsu_cancel_wait | vpu_cancel_wait; //no use
  assign bank_rsp_cancel_m2   = icu_flush_m2 | lsu_flush_m2; //no use

end else begin: d_flush_nowait
 
  assign flush_id_chk_m2    = dff_ppln_id_m2_q;

  assign icu_flush_m2    = (flush_id_chk_m2[ID_W-1 -: 4] == EXT_ID_ICU) & icu_flush;   //来自icu的flush有效
  assign icu_cancel_m2   = (flush_id_chk_m2[ID_W-1 -: 4] == EXT_ID_ICU) & icu_cancel;  //来自icu的cancel有效

  // Compare whether id is younger than flush_id.
  // - Wrap_bit equals, index (exclude wrap_bit) greater than or equal flush_index.
  // - Wrap_bit not equal, index (exclude wrap_bit) less than flush_index.
  assign lsu_flush_m2 = ((flush_id_chk_m2[ID_W-1 -: 4] == EXT_ID_LSU0) |  //当id指示的是LSU0
                         (flush_id_chk_m2[ID_W-1 -: 4] == EXT_ID_LSU1) )  //当id指示的LSU1
                      & lsu_flush //lsu的flush有效
                      & ( (flush_id_chk_m2[LSQID_W-1]   ^  lsu_flush_id[LSQID_W-1])    ? //绕回位不同，则比较索引
                          (flush_id_chk_m2[LSQID_W-2:0] <  lsu_flush_id[LSQID_W-2:0])  : //索引小于flush_id
                          (flush_id_chk_m2[LSQID_W-2:0] >= lsu_flush_id[LSQID_W-2:0]) ); //索引大于等于flush_id

  assign lsu_cancel_m2 = (flush_id_chk_m2[ID_W-1 -: 4] == EXT_ID_LSU0) & lsu_cancel[0] |//当id指示的是LSU0
                         (flush_id_chk_m2[ID_W-1 -: 4] == EXT_ID_LSU1) & lsu_cancel[1] ;//当id指示的是LSU1

  assign vpu_cancel_m2 = (flush_id_chk_m2[ID_W-1 -: 4] == EXT_ID_VPU0) & vpu_cancel[0] |//当id指示的是VPU0
                         (flush_id_chk_m2[ID_W-1 -: 4] == EXT_ID_VPU1) & vpu_cancel[1] ;//当id指示的是VPU1

  // NO_TCM_WAIT: rsp_m3 should be canceled
  assign bank_rsp_cancel_m2 = icu_flush_m2 | icu_cancel_m2 | lsu_flush_m2 | lsu_cancel_m2 | vpu_cancel_m2; //当m2的该信号为1时，m2的info信息无法流到m2
 
end

//=================================================================================
// TCM Pipeline Register
//=================================================================================

// ICU and LSU response at m2 stage, without ecc correction.
// SBU and SLV-BUS resposne at m3 stage, with ecc correction.
// However all pipeline_valid types are registered at M2 and M3,
// we'll distinguish M3 response from M2 response in TCU top.
 
//---------------------------------------
//            M1 Stage
//---------------------------------------
assign ppln_vld_m1     = bank_req_vld_m1 & bank_req_rdy_m1;  //ppln_vld_m1是m1阶段的有效信号，表示请求在m1阶段有效
assign ppln_addr_m1    = bank_req_addr_m1 ;//ppln_addr_m1是m1阶段的地址信号，表示请求在m1阶段地址
assign ppln_id_m1      = bank_req_id_m1   ;//ppln_id_m1是m1阶段的id信号，表示请求在m1阶段id
assign ppln_wr_m1      = bank_req_wr_m1   ;//ppln_wr_m1是m1阶段的写信号，表示请求在m1阶段写

assign bank_req_rdy_m1 = ~bank_self_wr_m3; //bank_self_wr_m3是m1阶段的写信号，表示请求在m1阶段写
 
if (WAIT_EN) begin: g_ppln_wait
// If TCM_WAIT enable, there is a stage between m1 and m2 called 'wait'
// load req send at m1, and rdata still return at m2, however there is a 'wait' stage between m1 and m2
//---------------------------------------
//          TCM_WAIT Stage
//---------------------------------------
  assign dff_ppln_vld_wait_set  = ppln_vld_m1; //no use
  assign dff_ppln_vld_wait_clr  = dff_ppln_vld_wait_q; //no use
  assign dff_ppln_vld_wait_en   = dff_ppln_vld_wait_set | dff_ppln_vld_wait_clr;//no use
  assign dff_ppln_vld_wait_d    = dff_ppln_vld_wait_set; //no use

  `WDFFER(dff_ppln_vld_wait_q      , dff_ppln_vld_wait_d  , dff_ppln_vld_wait_en, clk, rst_n) //no use
  `WDFFER(dff_ppln_wr_wait_q       , ppln_wr_m1           , ppln_vld_m1         , clk, rst_n) //no use
  `WDFFER(dff_ppln_addr_wait_q     , ppln_addr_m1         , ppln_vld_m1         , clk, rst_n) //no use
  `WDFFER(dff_ppln_id_wait_q       , ppln_id_m1           , ppln_vld_m1         , clk, rst_n) //no use
  `WDFFER(dff_ppln_data_dest_wait_q, bank_req_data_dest_m1, ppln_vld_m1         , clk, rst_n) //no use

//---------------------------------------
//            M2 Stage
//---------------------------------------
  assign dff_ppln_vld_m2_set = dff_ppln_vld_wait_q & ~bank_rsp_cancel_wait; //no use
  assign dff_ppln_vld_m2_clr = dff_ppln_vld_m2_q;//no use
  assign dff_ppln_vld_m2_en  = dff_ppln_vld_m2_set | dff_ppln_vld_m2_clr;//no use
  assign dff_ppln_vld_m2_d   = dff_ppln_vld_m2_set;//no use

  assign dff_ppln_info_m2_en = dff_ppln_vld_wait_q;//no use

  assign dff_ppln_wr_m2_d        = dff_ppln_wr_wait_q;//no use
  assign dff_ppln_addr_m2_d      = dff_ppln_addr_wait_q;//no use
  assign dff_ppln_id_m2_d        = dff_ppln_id_wait_q;//no use
  assign dff_ppln_rdata_m2_d     = ram_rdata_m2;//no use
  assign dff_ppln_data_dest_m2_d = dff_ppln_data_dest_wait_q;//no use

  `WDFFER(dff_ppln_vld_m2_q      , dff_ppln_vld_m2_d      , dff_ppln_vld_m2_en , clk, rst_n)//no use
  `WDFFER(dff_ppln_wr_m2_q       , dff_ppln_wr_m2_d       , dff_ppln_info_m2_en, clk, rst_n)//no use
  `WDFFER(dff_ppln_addr_m2_q     , dff_ppln_addr_m2_d     , dff_ppln_info_m2_en, clk, rst_n)//no use
  `WDFFER(dff_ppln_id_m2_q       , dff_ppln_id_m2_d       , dff_ppln_info_m2_en, clk, rst_n)//no use
  `WDFFER(dff_ppln_rdata_m2_q    , dff_ppln_rdata_m2_d    , dff_ppln_info_m2_en, clk, rst_n)//no use
  `WDFFER(dff_ppln_data_dest_m2_q, dff_ppln_data_dest_m2_d, dff_ppln_info_m2_en, clk, rst_n)//no use

  assign ram_rdata = dff_ppln_rdata_m2_q;//no use
 
  // set at m2 stage(if TCM_WAIT), whatever flush or cancel
  // only using for bank_rsp_vld_ras
  assign dff_ppln_vld_m2_ras_set = dff_ppln_vld_wait_q;//no use
  assign dff_ppln_vld_m2_ras_clr = dff_ppln_vld_m2_ras_q;//no use
  assign dff_ppln_vld_m2_ras_en  = dff_ppln_vld_m2_ras_set | dff_ppln_vld_m2_ras_clr;//no use
  assign dff_ppln_vld_m2_ras_d   = dff_ppln_vld_m2_ras_set;//no use
 
  `WDFFER(dff_ppln_vld_m2_ras_q, dff_ppln_vld_m2_ras_d, dff_ppln_vld_m2_ras_en, clk, rst_n)//no use
 
end else begin: g_ppln_nowait
// If NO TCM_WAIT, the stage after m1 is m2 
  assign dff_ppln_vld_m2_set = ppln_vld_m1; //ppln_vld_m1是m1阶段的有效信号，表示请求在m1阶段有效
  assign dff_ppln_vld_m2_clr = dff_ppln_vld_m2_q; //dff_ppln_vld_m2_q是m2阶段的有效信号，表示请求在m2阶段有效
  assign dff_ppln_vld_m2_en  = dff_ppln_vld_m2_set | dff_ppln_vld_m2_clr; //dff_ppln_vld_m2_set和dff_ppln_vld_m2_clr是m2阶段的有效信号，表示请求在m2阶段有效
  assign dff_ppln_vld_m2_d   = dff_ppln_vld_m2_set; //dff_ppln_vld_m2_d是m2阶段的有效信号，表示请求在m2阶段有效

  assign dff_ppln_info_m2_en = ppln_vld_m1; //ppln_vld_m1是m1阶段的有效信号，表示请求在m1阶段有效

  assign dff_ppln_wr_m2_d        = ppln_wr_m1; //ppln_wr_m1是m1阶段的写信号，表示请求在m1阶段写
  assign dff_ppln_addr_m2_d      = ppln_addr_m1; //ppln_addr_m1是m1阶段的地址信号，表示请求在m1阶段地址
  assign dff_ppln_id_m2_d        = ppln_id_m1; //ppln_id_m1是m1阶段的id信号，表示请求在m1阶段id
  assign dff_ppln_data_dest_m2_d = bank_req_data_dest_m1; //bank_req_data_dest_m1是m1阶段的data_dest信号，表示请求在m1阶段data_dest

  `WDFFER(dff_ppln_vld_m2_q      , dff_ppln_vld_m2_d      , dff_ppln_vld_m2_en , clk, rst_n) //dff_ppln_vld_m2_q是m2阶段的有效信号，表示请求在m2阶段有效
  `WDFFER(dff_ppln_wr_m2_q       , dff_ppln_wr_m2_d       , dff_ppln_info_m2_en, clk, rst_n) //dff_ppln_wr_m2_q是m2阶段的写信号，表示请求在m2阶段写
  `WDFFER(dff_ppln_addr_m2_q     , dff_ppln_addr_m2_d     , dff_ppln_info_m2_en, clk, rst_n) //dff_ppln_addr_m2_q是m2阶段的地址信号，表示请求在m2阶段地址
  `WDFFER(dff_ppln_id_m2_q       , dff_ppln_id_m2_d       , dff_ppln_info_m2_en, clk, rst_n) //dff_ppln_id_m2_q是m2阶段的id信号，表示请求在m2阶段id
  `WDFFER(dff_ppln_data_dest_m2_q, dff_ppln_data_dest_m2_d, dff_ppln_info_m2_en, clk, rst_n) //dff_ppln_data_dest_m2_q是m2阶段的data_dest信号，表示请求在m2阶段data_dest
 
  assign ram_rdata = ram_rdata_m2; //ram_rdata_m2是m2阶段的读数据，表示请求在m2阶段读数据

end

//---------------------------------------
//            M3 Stage
//---------------------------------------
assign dff_ppln_vld_m3_set  = dff_ppln_vld_m2_q & ~bank_rsp_cancel_m2;    //当m2 vld有效，且m2的rsp_cancel无效，则set有效
assign dff_ppln_vld_m3_clr  = dff_ppln_vld_m3_q;                          //当m3 vld有效，则clr有效
assign dff_ppln_vld_m3_en   = dff_ppln_vld_m3_set | dff_ppln_vld_m3_clr;  //当set有效，或者clr有效，则en有效
assign dff_ppln_vld_m3_d    = dff_ppln_vld_m3_set;                        //当set有效，则d为set

assign dff_ppln_id_m3_en    = dff_ppln_vld_m2_q;                          //dff_ppln_vld_m2_q是m2阶段的有效信号，表示请求在m2阶段有效
assign dff_ppln_rdata_m3_en = dff_ppln_vld_m2_q;                          //dff_ppln_vld_m2_q是m2阶段的有效信号，表示请求在m2阶段有效

`WDFFER(dff_ppln_vld_m3_q      , dff_ppln_vld_m3_d      , dff_ppln_vld_m3_en  , clk, rst_n) //vld打拍到m3
`WDFFER(dff_ppln_wr_m3_q       , dff_ppln_wr_m2_q       , dff_ppln_vld_m2_q   , clk, rst_n) //wr打拍到m3
`WDFFER(dff_ppln_addr_m3_q     , dff_ppln_addr_m2_q     , dff_ppln_vld_m2_q   , clk, rst_n) //addr打拍到m3
`WDFFER(dff_ppln_id_m3_q       , dff_ppln_id_m2_q       , dff_ppln_id_m3_en   , clk, rst_n) //id打拍到m3
`WDFFER(dff_ppln_rdata_m3_q    , ram_rdata[DATA_W-1:0]  , dff_ppln_rdata_m3_en, clk, rst_n) //rdata打拍到m3
`WDFFER(dff_ppln_data_dest_m3_q, dff_ppln_data_dest_m2_q, dff_ppln_vld_m2_q   , clk, rst_n) //data_dest打拍到m3

// IF there is a write req to same address happens in m2, the ECC self_correct should be given up
assign m2_addr_match = (dff_ppln_addr_m2_q[RAM_ADDR_OFFS +: RAM_ADDR_W] == ram_addr_m1) & ram_cs_m1 & ram_wr_m1;
 
//=================================================================================
// Partial Merge and ECC Encode/Decode
//=================================================================================
assign pre_enc_wdata_m3 = atop_self_wr_m3   ? atop_rslt_m3     :
                          bank_bein_ptwr_m3 ? bank_pt_wdata_m3 : post_cor_rdata_m3;   

assign pre_enc_wstrb_m3 = hold_wstrb;
 
if (ECC_EN) begin : G_ECC

localparam ECC_CODE_W = RAM_DATA_W - DATA_W; //ECC_CODE_W是ECC编码的位数，等于RAM_DATA_W（72）减去DATA_W（64），等于8
 
logic                  dff_bank_ptwr_wait_set; //等待阶段部分写设置
logic                  dff_bank_ptwr_wait_clr;  //等待阶段部分写清除
logic                  dff_bank_ptwr_wait_en;   //等待阶段部分写使能
logic                  dff_bank_ptwr_wait_d;    //等待阶段部分写数据
logic                  dff_bank_ptwr_wait_q;    //等待阶段部分写标志
 
logic [DATA_W-1:0]     bank_wen_pre; //m1阶段写使能
logic                  dff_bank_ptwr_m2_set; //m2阶段部分写设置
logic                  dff_bank_ptwr_m2_clr; //m2阶段部分写清除
logic                  dff_bank_ptwr_m2_en;  //m2阶段部分写使能
logic                  dff_bank_ptwr_m2_d;   //m2阶段部分写数据
logic                  dff_bank_ptwr_m2_q;   //m2阶段部分写标志
logic                  dff_bank_ptwr_m3_set; //m3阶段部分写设置
logic                  dff_bank_ptwr_m3_clr; //m3阶段部分写清除
logic                  dff_bank_ptwr_m3_en;  //m3阶段部分写使能
logic                  dff_bank_ptwr_m3_d;   //m3阶段部分写数据
logic                  dff_bank_ptwr_m3_q;   //m3阶段部分写标志
logic                  dff_ecc_en_m2;        //m2阶段ECC使能
logic [ECC_CODE_W-1:0] ecc_enc_code;        //ECC编码
logic [ECC_CODE_W-1:0] ecc_syndrome_m2;     //m2阶段ECC校验码
logic [ECC_CODE_W-1:0] ecc_syndrome_m3;     //m3阶段ECC校验码

assign into_partial_m1 = ppln_vld_m1 & partial_wr & csr_ecc_en; //部分写（Partial Write）状态。当请求有效、部分写使能且ECC使能时，进入部分写状态。
 
for (genvar i=0; i<DATA_W; i++) begin: G_WEN_PRE
  assign bank_wen_pre[i] = bank_req_wstrb_m1[i/8];
end

// If ECC_EN, do not support partial write to memory
// 当ecc有效时，不支持m1的部分写操作，如果不支持ecc，将编码为全置为1，为什么把编码全部置为1？todo
assign bank_wen_m1 = csr_ecc_en ? {RAM_DATA_W{1'b1}} : {{ECC_CODE_W{1'b1}}, bank_wen_pre};

//---------------------------------------
//   Read-Modify-Write State Register
//---------------------------------------  
if (WAIT_EN) begin: g_ecc_ptwr_wait

  assign dff_bank_ptwr_wait_set = into_partial_m1;  //no use
  assign dff_bank_ptwr_wait_clr = dff_bank_ptwr_wait_q;//no use
  assign dff_bank_ptwr_wait_en  = dff_bank_ptwr_wait_set | dff_bank_ptwr_wait_clr;//no use
  assign dff_bank_ptwr_wait_d   = dff_bank_ptwr_wait_set;//no use
 
  `WDFFER(dff_bank_ptwr_wait_q, dff_bank_ptwr_wait_d, dff_bank_ptwr_wait_en, clk, rst_n) //no use
 
  assign bank_bein_ptwr_wait = dff_bank_ptwr_wait_q; //no use
 
  assign dff_bank_ptwr_m2_set = dff_bank_ptwr_wait_q;    //no use
  assign dff_bank_ptwr_m2_clr = dff_bank_ptwr_m2_q;      //no use
  assign dff_bank_ptwr_m2_en  = dff_bank_ptwr_m2_set | dff_bank_ptwr_m2_clr;//no use
  assign dff_bank_ptwr_m2_d   = dff_bank_ptwr_m2_set;//no use

end else begin: g_ecc_ptwr_nowait
 
  assign dff_bank_ptwr_m2_set = into_partial_m1;     //m1部分写有效
  assign dff_bank_ptwr_m2_clr = dff_bank_ptwr_m2_q;  //Q为1时使能D触发器
  assign dff_bank_ptwr_m2_en  = dff_bank_ptwr_m2_set | dff_bank_ptwr_m2_clr; //D或者Q为1时都使能D触发器
  assign dff_bank_ptwr_m2_d   = dff_bank_ptwr_m2_set; //输入D端
 
end 

assign dff_bank_ptwr_m3_set = dff_bank_ptwr_m2_q;     //m2部分写有效
assign dff_bank_ptwr_m3_clr = dff_bank_ptwr_m3_q;     //Q为1时使能D触发器
assign dff_bank_ptwr_m3_en  = dff_bank_ptwr_m3_set | dff_bank_ptwr_m3_clr; //D或者Q为1时都使能D触发器
assign dff_bank_ptwr_m3_d   = dff_bank_ptwr_m3_set;  //输入D端
 
`WDFFER(dff_bank_ptwr_m2_q, dff_bank_ptwr_m2_d, dff_bank_ptwr_m2_en, clk, rst_n) //将mask读后写打拍到m2
`WDFFER(dff_bank_ptwr_m3_q, dff_bank_ptwr_m3_d, dff_bank_ptwr_m3_en, clk, rst_n) //将mask读后写打拍到m3

assign bank_bein_ptwr_m2     = dff_bank_ptwr_m2_q;                    //m2 begin partial write signal
assign bank_bein_ptwr_m3_pre = dff_bank_ptwr_m3_q;                    //m3 begin partial write signal
assign bank_bein_ptwr_m3     = dff_bank_ptwr_m3_q & ~ecc_dec_ded_m3;  // bank will not self_correct when ECC DED
 
//以byte为单位进行for循环，如果循环过程中写wstrb有效，那么使用写的数据byte，否则使用m2读出数据的byte。将组合好的数据作为新的写数据
for (genvar i=0; i<(DATA_W/8); i++) begin: g_bank_data_merge
  assign bank_pt_wdata_m3[i*8 +: 8] = hold_wstrb[i] ? hold_wdata[i*8 +: 8] : post_cor_rdata_m3[i*8 +: 8]; //对byte进行for循环
end

//---------------------------------------
//        ECC Encode
//---------------------------------------
// ECC Encode only works at m3 stage(for tcm self-write), the m1 stage wdata are already encoded.
if ((DATA_W == 32)) begin : g_ecc_enc_32
  wing_cbb_ecc_enc32 u_bank_ecc_enc_32(.data_i(pre_enc_wdata_m3), .enc_o(ecc_enc_code));
end else if ((DATA_W == 64)) begin : g_ecc_enc_64 //no use
  wing_cbb_ecc_enc64 u_bank_ecc_enc_64(.data_i(pre_enc_wdata_m3), .enc_o(ecc_enc_code)); //no use
end//no use

assign post_enc_wdata_m3 = {ecc_enc_code, pre_enc_wdata_m3}; //将校验码和修正的数据进行拼接
assign post_enc_wen_m3   = {RAM_DATA_W{1'b1}}; //自写的bit使能全部为1
 
//---------------------------------------
//        ECC Decode (Error Detect)
//---------------------------------------
// ECC error is detected in m2 stage
if ((DATA_W == 32)) begin : g_ecc_errdet_32 //error check
  wing_cbb_ecc_det32 u_bank_ecc_det32(.data_i(ram_rdata), .syndrome_o(ecc_syndrome_m2), .error_detected(), .single_error_o(ecc_dec_sec_m2), .double_error_o(ecc_dec_ded_m2));
end else if ((DATA_W == 64)) begin : g_ecc_errdet_64 //no use
  wing_cbb_ecc_det64 u_bank_ecc_det64(.data_i(ram_rdata), .syndrome_o(ecc_syndrome_m2), .error_detected(), .single_error_o(ecc_dec_sec_m2), .double_error_o(ecc_dec_ded_m2));
end //no use

assign dff_ecc_en_m2 = dff_ppln_vld_m2_q & csr_ecc_en; //
 
`WDFFER(ecc_syndrome_m3, ecc_syndrome_m2, dff_ecc_en_m2, clk, rst_n)
`WDFFER(ecc_dec_sec_m3 , ecc_dec_sec_m2 , dff_ecc_en_m2, clk, rst_n)
`WDFFER(ecc_dec_ded_m3 , ecc_dec_ded_m2 , dff_ecc_en_m2, clk, rst_n)
`WDFFER(m2_addr_match_q, m2_addr_match  , dff_ecc_en_m2, clk, rst_n)
 
//--------------------------------------
//        ECC Decode (Error Correct)
//---------------------------------------
// ECC error (1-bit) is corrected in m3 stage
if ((DATA_W == 32)) begin : g_ecc_errcorr_32
  wing_cbb_ecc_cor32 u_bank_ecc_cor32(.data_i(dff_ppln_rdata_m3_q), .syndrome_i(ecc_syndrome_m3), .data_o(post_cor_rdata_m3));
end else if ((DATA_W == 64)) begin : g_ecc_dec_64
  wing_cbb_ecc_cor64 u_bank_ecc_cor64(.data_i(dff_ppln_rdata_m3_q), .syndrome_i(ecc_syndrome_m3), .data_o(post_cor_rdata_m3));
end
//当m3有效，且m3的wr无效，且ecc单比特错误有效，且m2的地址不匹配时，认为bank自写有效
assign bank_ecc_self_wr_m3 = dff_ppln_vld_m3_q & ~dff_ppln_wr_m3_q & ecc_dec_sec_m3 & ~m2_addr_match_q;
 
end else begin : G_NOECC

assign into_partial_m1     = 1'b0; //no use
 
for (genvar i=0; i<RAM_DATA_W; i++) begin: G_WEN_M1 //no use
  assign bank_wen_m1[i] = bank_req_wstrb_m1[i/8];//no use
end//no use

if (WAIT_EN) begin:g_noecc_ptwr//no use
  assign bank_bein_ptwr_wait = 1'b0;//no use
end//no use
 
assign bank_bein_ptwr_m2     = 1'b0;//no use
assign bank_bein_ptwr_m3_pre = 1'b0; //no use
assign bank_bein_ptwr_m3     = 1'b0; //no use
assign bank_pt_wdata_m3      = {DATA_W{1'b0}}; //no use
assign post_enc_wdata_m3     = pre_enc_wdata_m3;//no use
 
for (genvar i=0; i<RAM_DATA_W; i++) begin: G_WEN_M3//no use
  assign post_enc_wen_m3[i] = pre_enc_wstrb_m3[i/8];//no use
end//no use

assign ecc_dec_sec_m2      = 1'b0;//no use
assign ecc_dec_sec_m3      = 1'b0;//no use
assign ecc_dec_ded_m2      = 1'b0;//no use
assign ecc_dec_ded_m3      = 1'b0;//no use
assign post_cor_rdata_m3   = dff_ppln_rdata_m3_q;//no use
assign bank_ecc_self_wr_m3 = 1'b0;//no use

end    // ECC_EN
 
//=================================================================================
// ATOP
//=================================================================================

if (ATOP_EN) begin : G_ATOP
 
logic atop_be;                    //原子操作大小端标志
logic [DATA_W-1:0] hold_wdata_le; //原子操作写数据
logic [DATA_W-1:0] bank_rdata_le; //原子操作读数据
logic [DATA_W-1:0] atop_rslt_be;  //原子操作结果
logic atop_is_comp;                //原子操作比较
logic atop_is_swap;                //原子操作交换
logic atop_is_ldst;                //原子操作加载/存储
logic atop_is_add;                 //原子操作加法
logic atop_is_clr;                 //原子操作清除
logic atop_is_eor;                 //原子操作异或
logic atop_is_set;                 //原子操作设置
logic atop_is_smax;                //原子操作有符号最大值
logic atop_is_smin;                //原子操作有符号最小值
logic atop_is_umax;                //原子操作无符号最大值
logic atop_is_umin;                //原子操作无符号最小值
logic atop_is_signed;              //原子操作有符号
logic atop_is_sub;                 //原子操作减法
logic atop_comp_equal;             //原子操作比较相等
logic [DATA_W-1:0] atop_adder_a;   //原子操作加法器A
logic              atop_adder_a_sign;//原子操作加法器A符号
logic [DATA_W  :0] atop_adder_a_ext;//原子操作加法器A扩展
logic [DATA_W-1:0] atop_adder_b;   //原子操作加法器B
logic              atop_adder_b_sign;//原子操作加法器B符号
logic [DATA_W:0]   atop_adder_b_ext;//原子操作加法器B扩展
logic [DATA_W:0]   atop_adder_b_rvs;//原子操作加法器B反转
logic atop_adder_ci;               //原子操作加法器进位
logic atop_adder_co;               //原子操作加法器进位
logic [DATA_W-1:0] atop_adder_rslt_le;//原子操作加法器结果
logic [DATA_W-1:0] atop_rslt_comp;   //原子操作比较结果
logic [DATA_W-1:0] atop_rslt_swap;   //原子操作交换结果
logic [DATA_W-1:0] atop_rslt_add;    //原子操作加法结果
logic [DATA_W-1:0] atop_rslt_clr;    //原子操作清除结果
logic [DATA_W-1:0] atop_rslt_eor;    //原子操作异或结果
logic [DATA_W-1:0] atop_rslt_set;    //原子操作设置结果
logic [DATA_W-1:0] atop_rslt_max;    //原子操作最大值结果
logic [DATA_W-1:0] atop_rslt_min;    //原子操作最小值结果
logic [DATA_W-1:0] atop_rslt_le;     //原子操作结果
 
assign into_atomic_m1 = ppln_vld_m1 & atop_wr; //当m1有效，且原子操作写有效时，认为原子操作进行中有效

//---------------------------------------
//        ATOP State Register
//---------------------------------------
// ATOP stage:
// M1: load req to memory
// M2: rdata rsp from memory
// M3: atomic operation (modify the data) and write back to memory
 
if (WAIT_EN) begin: g_atop_wait

  assign dff_ppln_atop_infly_wait_en  = into_atomic_m1 | dff_ppln_atop_infly_wait_q; //nouse
  assign dff_ppln_atop_infly_wait_d   = into_atomic_m1; //nouse

  `WDFFER(dff_ppln_atop_infly_wait_q, dff_ppln_atop_infly_wait_d, dff_ppln_atop_infly_wait_en, clk, rst_n) //no use
 
  assign bank_atop_infly_wait       = dff_ppln_atop_infly_wait_q; //no use
  assign dff_ppln_atop_infly_m2_set = dff_ppln_atop_infly_wait_q; //no use

end else begin: g_atop_nowait 
 
  assign dff_ppln_atop_infly_m2_set = into_atomic_m1;
 
end

// ATOP (Atomic Operation) pipeline control signals for M2 stage
assign dff_ppln_atop_infly_m2_clr = dff_ppln_atop_infly_m2_q;    // Clear signal: clear when current value is 1
assign dff_ppln_atop_infly_m2_en  = dff_ppln_atop_infly_m2_set | dff_ppln_atop_infly_m2_clr;  // Enable signal: enable when set or clear
assign dff_ppln_atop_infly_m2_d   = dff_ppln_atop_infly_m2_set;  // Data input: set to 1 when set signal is active

// ATOP pipeline control signals for M3 stage  
assign dff_ppln_atop_infly_m3_set = dff_ppln_atop_infly_m2_q;    // Set signal: propagate from M2 stage
assign dff_ppln_atop_infly_m3_clr = dff_ppln_atop_infly_m3_q;    // Clear signal: clear when current value is 1
assign dff_ppln_atop_infly_m3_en  = dff_ppln_atop_infly_m3_set | dff_ppln_atop_infly_m3_clr;  // Enable signal: enable when set or clear
assign dff_ppln_atop_infly_m3_d   = dff_ppln_atop_infly_m3_set;  // Data input: set to 1 when set signal is active 
 
`WDFFER(dff_ppln_atop_infly_m2_q, dff_ppln_atop_infly_m2_d, dff_ppln_atop_infly_m2_en, clk, rst_n) //m2原子操作进行中标志
`WDFFER(dff_ppln_atop_infly_m3_q, dff_ppln_atop_infly_m3_d, dff_ppln_atop_infly_m3_en, clk, rst_n) //m3原子操作进行中标志
 
assign bank_atop_infly_m2   = dff_ppln_atop_infly_m2_q; //m2原子操作进行中标志
assign bank_atop_infly_m3   = dff_ppln_atop_infly_m3_q; //m3原子操作进行中标志
assign bank_atop_b_infly_m3 = dff_ppln_atop_infly_m3_q; //m3原子操作进行中标志
assign bank_atop_r_infly_m3 = dff_ppln_atop_infly_m3_q & ~(hold_atop[5:4] == 2'b01); //m3原子操作进行中标志
 
//---------------------------------------
//          Endianess Transfer
//---------------------------------------
// the data (both wdata and rdata) should be transfered to little end before data modification in m3 stage
 
assign atop_be = hold_atop[3];  // atop under big_end

for (genvar a=0; a<DATA_W/8; a++) begin: g_end_trans
 
  assign hold_wdata_le[a*8 +: 8] = hold_wdata       [((DATA_W/8)-1-a)*8 +: 8]; //将大端数据转换为小端数据
  assign bank_rdata_le[a*8 +: 8] = post_cor_rdata_m3[((DATA_W/8)-1-a)*8 +: 8]; //将纠错后的数据转换为小端数据
  assign atop_rslt_be [a*8 +: 8] = atop_rslt_le     [((DATA_W/8)-1-a)*8 +: 8]; //将原子操作结果转换为小端数据
 
end

//---------------------------------------
//           ATOP Calculation
//---------------------------------------
assign atop_is_comp = hold_atop[5:0] == 6'b110001; //原子操作比较
assign atop_is_swap = hold_atop[5:0] == 6'b110000; //原子操作交换

assign atop_is_ldst = (hold_atop[5:4] == 2'b10) | (hold_atop[5:4] == 2'b01); //原子操作加载/存储
 
assign atop_is_add  = atop_is_ldst & (hold_atop[2:0] == 3'b000); //原子操作加法
assign atop_is_clr  = atop_is_ldst & (hold_atop[2:0] == 3'b001); //原子操作清除
assign atop_is_eor  = atop_is_ldst & (hold_atop[2:0] == 3'b010); //原子操作异或
assign atop_is_set  = atop_is_ldst & (hold_atop[2:0] == 3'b011); //原子操作设置
assign atop_is_smax = atop_is_ldst & (hold_atop[2:0] == 3'b100); //原子操作有符号最大值
assign atop_is_smin = atop_is_ldst & (hold_atop[2:0] == 3'b101); //原子操作有符号最小值
assign atop_is_umax = atop_is_ldst & (hold_atop[2:0] == 3'b110); //原子操作无符号最大值
assign atop_is_umin = atop_is_ldst & (hold_atop[2:0] == 3'b111); //原子操作无符号最小值

assign atop_is_signed = atop_is_smax | atop_is_smin; //原子操作有符号
assign atop_is_sub    = atop_is_smax | atop_is_smin | atop_is_umax | atop_is_umin;
 
assign atop_comp_equal = (hold_cmp_val == post_cor_rdata_m3); //原子操作比较相等

// wdata from SBU 
assign atop_adder_a      = atop_be ? hold_wdata_le : hold_wdata; //根据字节序模式选择写数据的格式
assign atop_adder_a_sign = atop_is_signed ? atop_adder_a[31] : 1'b0; //根据操作类型决定符号扩展位
assign atop_adder_a_ext  = {atop_adder_a_sign, atop_adder_a}; //符号扩展

// rdata from RAM
assign atop_adder_b      = atop_be ? bank_rdata_le : post_cor_rdata_m3; //原子操作加法器B
assign atop_adder_b_sign = atop_is_signed ? atop_adder_b[31] : 1'b0; //原子操作加法器B符号
assign atop_adder_b_ext  = {atop_adder_b_sign, atop_adder_b}; //原子操作加法器B扩展
assign atop_adder_b_rvs  = atop_is_sub ? ~atop_adder_b_ext : atop_adder_b_ext; //原子操作加法器B反转
 
assign atop_adder_ci     = atop_is_sub; //原子操作加法器进位
 
assign {atop_adder_co, atop_adder_rslt_le} = atop_adder_a_ext + atop_adder_b_rvs + atop_adder_ci; //原子操作加法器结果
 
assign atop_rslt_comp = atop_be ? hold_wdata_le : hold_wdata; //原子操作比较结果
assign atop_rslt_swap = atop_be ? hold_wdata_le : hold_wdata; //原子操作交换结果
assign atop_rslt_add  = atop_adder_rslt_le; //原子操作加法结果
assign atop_rslt_clr  = atop_adder_b & ~atop_adder_a; //原子操作清除结果
assign atop_rslt_eor  = atop_adder_b ^  atop_adder_a; //原子操作异或结果
assign atop_rslt_set  = atop_adder_b |  atop_adder_a; //原子操作设置结果
assign atop_rslt_max  = atop_adder_co ? atop_adder_b : atop_adder_a; //原子操作最大值结果
assign atop_rslt_min  = atop_adder_co ? atop_adder_a : atop_adder_b; //原子操作最小值结果
 
assign atop_self_wr_m3 = dff_ppln_atop_infly_m3_q & (~atop_is_comp | atop_comp_equal) & ~ecc_dec_ded_m3; //m3原子操作自写有效
assign atop_rslt_m3    = atop_be ? atop_rslt_be : atop_rslt_le; //如果大端，则返回大端结果，否则返回小端结果

//原子操作结果选择
assign atop_rslt_le = {32{atop_is_comp}} & atop_rslt_comp | //原子比较操作
                      {32{atop_is_swap}} & atop_rslt_swap | //原子交换操作结果
                      {32{atop_is_add }} & atop_rslt_add  | //原子加法操作结果
                      {32{atop_is_clr }} & atop_rslt_clr  | //原子清除操作结果
                      {32{atop_is_eor }} & atop_rslt_eor  | //原子异或操作结果
                      {32{atop_is_set }} & atop_rslt_set  | //原子设置操作结果
                      {32{atop_is_smax}} & atop_rslt_max  | //原子有符号最大值操作结果
                      {32{atop_is_smin}} & atop_rslt_min  | //原子有符号最小值操作结果
                      {32{atop_is_umax}} & atop_rslt_max  | //原子无符号最大值操作结果
                      {32{atop_is_umin}} & atop_rslt_min  ; //原子无符号最小值操作结果

end else begin : G_NOATOP
 
assign into_atomic_m1 = 1'b0; //原子操作进行中标志
 
if (WAIT_EN) begin:g_noatop_wait
  assign bank_atop_infly_wait = 1'b0; //等待阶段原子操作进行中标志
end

assign bank_atop_infly_m2   = 1'b0; //m2原子操作进行中标志
assign bank_atop_infly_m3   = 1'b0;
assign bank_atop_b_infly_m3 = 1'b0;
assign bank_atop_r_infly_m3 = 1'b0;
 
assign atop_self_wr_m3 = 1'b0; //m3原子操作自写有效
assign atop_rslt_m3    = {DATA_W{1'b0}}; //原子操作结果
 
end // ATOP_EN

//=================================================================================
// Response Interface
//=================================================================================
if (WAIT_EN) begin: g_bank_busy_wait
 
  assign bank_busy = bank_bein_ptwr_wait | bank_bein_ptwr_m2 | bank_atop_infly_wait | bank_atop_infly_m2 | bank_self_wr_m3;//nouse
  assign bank_idle = ~(dff_ppln_vld_wait_q | dff_ppln_vld_m2_q | dff_ppln_vld_m3_q); //nouse
 
end else begin: g_bank_busy_nowait
 
  assign bank_busy = bank_bein_ptwr_m2 | bank_atop_infly_m2 | bank_self_wr_m3; //当m2有效，且m2的wr无效，且ecc单比特错误有效，且m2的地址不匹配时，认为bank自写有效
  assign bank_idle = ~(dff_ppln_vld_m2_q | dff_ppln_vld_m3_q); //当m2有效，且m3有效时，认为bank空闲
 
end

// ICU and LSU response at M2 stage, without ecc correction.
// 3'b000 - ICU
// 3'b001 - LSU[0]
// 3'b101 - LSU[1]
assign bank_rsp_vld_m2       = dff_ppln_vld_m2_q; //m2返回有效信号
assign bank_rsp_id_m2        = dff_ppln_id_m2_q; //m2返回id信号
assign bank_rsp_data_m2      = ram_rdata[DATA_W-1:0]; //m2返回源数据信号
assign bank_rsp_se_m2        = csr_ecc_en & (bank_bein_ptwr_m2 ? ecc_dec_sec_m2 : (~dff_ppln_wr_m2_q & ecc_dec_sec_m2)); //m2返回ecc单比特错误信号
assign bank_rsp_de_m2        = csr_ecc_en & (bank_bein_ptwr_m2 ? ecc_dec_ded_m2 : (~dff_ppln_wr_m2_q & ecc_dec_ded_m2)); //m2返回ecc双比特错误信号
assign bank_rsp_data_dest_m2 = dff_ppln_data_dest_m2_q; //no use
assign bank_rsp_addr_m2      = dff_ppln_addr_m2_q; //m2返回地址信号
 
// SBU, SLV-BUS and VPU resposne at M3 stage, with ecc correction.
// 3'b010 - SBU
// 3'b011 - SLV-BUS
assign bank_rsp_vld_m3       = dff_ppln_vld_m3_q; //m3返回有效信号
assign bank_rsp_id_m3        = dff_ppln_id_m3_q; //m3返回id信号
assign bank_rsp_data_m3      = post_cor_rdata_m3; //m3返回源数据信号
assign bank_rsp_se_m3        = csr_ecc_en & ((bank_atop_infly_m3 | bank_bein_ptwr_m3_pre) ? ecc_dec_sec_m3 : (~dff_ppln_wr_m3_q & ecc_dec_sec_m3)); //m3返回ecc单比特错误信号
assign bank_rsp_de_m3        = csr_ecc_en & ((bank_atop_infly_m3 | bank_bein_ptwr_m3_pre) ? ecc_dec_ded_m3 : (~dff_ppln_wr_m3_q & ecc_dec_ded_m3)); //m3返回ecc双比特错误信号
assign bank_rsp_data_dest_m3 = dff_ppln_data_dest_m3_q; //no use
assign bank_rsp_addr_m3      = dff_ppln_addr_m3_q; //m3返回地址信号
 
// Response Interface for RAS
if (WAIT_EN) begin: g_bank_ras_wait
  // TCM_WAIT: set when m2 stage
  assign bank_rsp_vld_ras      = dff_ppln_vld_m2_ras_q;// nouse
  assign bank_rsp_id_ras       = dff_ppln_id_m2_q;// nouse
  assign bank_rsp_se_ras       = csr_ecc_en & ((bank_atop_infly_m2 | bank_bein_ptwr_m2) ? ecc_dec_sec_m2 : (~dff_ppln_wr_m2_q & ecc_dec_sec_m2));// nouse
  assign bank_rsp_de_ras       = csr_ecc_en & ((bank_atop_infly_m2 | bank_bein_ptwr_m2) ? ecc_dec_ded_m2 : (~dff_ppln_wr_m2_q & ecc_dec_ded_m2));// nouse
  assign bank_rsp_wr_ras       = dff_ppln_addr_m2_q;// nouse
  assign bank_rsp_addr_ras     = dff_ppln_addr_m2_q;// nouse

end else begin: g_bank_ras_nowait
  // NO_TCM_WAIT: set when m2 stage
  assign bank_rsp_vld_ras      = dff_ppln_vld_m2_q; //m2返回有效信号
  assign bank_rsp_id_ras       = dff_ppln_id_m2_q; //m2返回id信号
  assign bank_rsp_se_ras       = csr_ecc_en & ((bank_atop_infly_m2 | bank_bein_ptwr_m2) ? ecc_dec_sec_m2 : (~dff_ppln_wr_m2_q & ecc_dec_sec_m2)); //m2返回ecc单比特错误信号
  assign bank_rsp_de_ras       = csr_ecc_en & ((bank_atop_infly_m2 | bank_bein_ptwr_m2) ? ecc_dec_ded_m2 : (~dff_ppln_wr_m2_q & ecc_dec_ded_m2)); //m2返回ecc双比特错误信号
  assign bank_rsp_wr_ras       = dff_ppln_wr_m2_q; //m2返回写信号
  assign bank_rsp_addr_ras     = dff_ppln_addr_m2_q; //m2返回地址信号
 
end

//=================================================================================
// Assertion
//=================================================================================

NO_ATOP_WHEN_DISABLE_A: assert property ( @(posedge clk) disable iff (!rst_n) 
  (ATOP_EN == 1'b0) |-> (into_atomic_m1 == 1'b0)
) else $fatal(1, "%m - should be no atop when disable ATOP_EN.");
 
endmodule
`include "chunjun_undefine.sv" 
